package org.tio.http.apitool.controller;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.http.apitool.HttpApiToolStarter;
import org.tio.http.apitool.page.ListPageable;
import org.tio.http.apitool.utils.HttpClientUtils;
import org.tio.http.apitool.utils.WebUtils;
import org.tio.http.apitool.vo.AjaxRespPojo;
import org.tio.http.common.HttpRequest;
import org.tio.http.server.annotation.RequestPath;
import org.tio.utils.hutool.StrUtil;
import org.tio.utils.json.Json;

import cn.hutool.core.io.FileUtil;

/**
 * @author tanyaowu
 */
@RequestPath(value = "/common/httpclient")
public class HttpApiToolController {

	private static Logger	log			= LoggerFactory.getLogger(HttpApiToolController.class);
	private static String	templateDir	= null;

	private static String getTemplateDir() {
		if (templateDir == null) {
			templateDir = HttpApiToolStarter.httpConfig.getPageRoot() + "/http-apitool-template";
		}

		return templateDir;
	}

	/**
	 * 将HttpRequest中{name4Name}和{name4Value}组装成相应的请求参数：params.put({name4Name}[i], {name4Value}[i]);
	 * @param request
	 * @param params
	 * @param name4Name
	 * @param name4Value
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static void appendParams(HttpRequest request, Map<String, Object> params, String name4Name, String name4Value) {
		Object[] paramNames = request.getParamArray(name4Name);//request.getParamValues(name4Name);
		Object[] paramValues = request.getParamArray(name4Value);//request.getParamValues(name4Value);
		if (paramNames != null) {
			for (int i = 0; i < paramNames.length; i++) {
				if (!StrUtil.isBlank((String) paramNames[i])) {
					if (params.containsKey(paramNames[i])) {
						Object obj = params.get(paramNames[i]);
						if (obj instanceof String) {
							List<Object> list = new ArrayList<Object>();
							list.add(obj);
							list.add(paramValues[i]);
							params.put((String) paramNames[i], list);
						} else {
							List<Object> list = (List) obj;
							list.add(paramValues[i]);
						}
					} else {
						params.put((String) paramNames[i], paramValues[i]);
					}
				}
			}
		}
	}

	/**
	 * 
	 * @param cookieHeaders
	 * @return
	 */
	public static String[] cookiesToStrings(List<Header> cookieHeaders) {
		String[] cookies = null;
		if (cookieHeaders != null && cookieHeaders.size() > 0) {
			cookies = new String[cookieHeaders.size()];
			int i = 0;
			for (Header header : cookieHeaders) {
				cookies[i++] = header.getValue();
			}
		}
		return cookies;
	}

	/**
	 * 
	 * @param tt_request_url
	 * @param request
	 * @param httpServletResponse
	 * @throws Exception
	 */
	@RequestPath(value = "/getCookie")
	public static AjaxRespPojo getCookie(String proxyHostName, Integer proxyPort, String proxySchemeName, String tt_request_url, String[] cookies, HttpRequest request,
	        String tt_method) throws Exception {
		HttpHost proxy = null;
		if (!StrUtil.isBlank(proxyHostName)) {
			proxy = new HttpHost(proxyHostName, proxyPort, proxySchemeName);
		}

		Map<String, Object> requestHeaders = new HashMap<String, Object>();
		appendParams(request, requestHeaders, "header_name", "header_value");

		try {
			if (cookies != null && cookies.length > 0) {
				for (String cookie : cookies) {
					if (cookie != null && !"".equals(cookie)) {
						requestHeaders.put("Cookie", cookie);
					}
				}
			}

			Map<String, Object> params = request.getParam();

			appendParams(request, params, "param_name", "param_value");
			List<Header> cookieHeaders = HttpClientUtils.getCookieHeaders(params, tt_request_url, HttpClientUtils.mapToHeaders(requestHeaders), tt_method, proxy);

			String[] _cookies = cookiesToStrings(cookieHeaders);

			return WebUtils.writeSuccess("操作成功", "", _cookies, request);
		} catch (Exception e) {
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	/**
	 * 
	 * @param proxyHostName
	 * @param proxyPort
	 * @param proxySchemeName
	 * @param tt_request_url
	 * @param request
	 * @param cookies
	 * @param tt_method
	 * @param httpServletResponse
	 * @param tt_requestbody
	 */
	@RequestPath(value = "/saveTemplate")
	public static AjaxRespPojo saveTemplate(String tt_request_url, HttpRequest request, String templateName, Boolean isAbspath, String[] header_name, String[] header_value,
	        String[] header_remark, String[] param_name, String[] param_value, String[] param_remark, String[] respremark_name, String[] respremark_value,
	        String[] respremark_remark) throws Exception {
		try {
			Map<String, List<Map<String, String>>> requestHeaders = new HashMap<String, List<Map<String, String>>>();
			Map<String, List<Map<String, String>>> requestParams = new HashMap<String, List<Map<String, String>>>();
			Map<String, List<Map<String, String>>> respremarks = new HashMap<String, List<Map<String, String>>>();

			if (header_name != null && header_name.length > 0) {
				int i = 0;
				for (String header_name1 : header_name) {
					List<Map<String, String>> ss = requestHeaders.get(header_name1);
					if (ss == null) {
						ss = new ArrayList<Map<String, String>>();
					}
					requestHeaders.put(header_name1, ss);

					Map<String, String> map = new HashMap<>();
					map.put("value", header_value[i]);
					map.put("remark", header_remark[i]);
					ss.add(map);
					i++;
				}
			}
			if (param_name != null && param_name.length > 0) {
				int i = 0;
				for (String param_name1 : param_name) {
					List<Map<String, String>> ss = requestParams.get(param_name1);
					if (ss == null) {
						ss = new ArrayList<Map<String, String>>();
					}
					requestParams.put(param_name1, ss);

					Map<String, String> map = new HashMap<>();
					map.put("value", param_value[i]);
					map.put("remark", param_remark[i]);
					ss.add(map);
					i++;
				}
			}
			if (respremark_name != null && respremark_name.length > 0) {
				int i = 0;
				for (String respremark_name1 : respremark_name) {
					List<Map<String, String>> ss = respremarks.get(respremark_name1);
					if (ss == null) {
						ss = new ArrayList<Map<String, String>>();
					}
					respremarks.put(respremark_name1, ss);

					Map<String, String> map = new HashMap<>();
					map.put("value", respremark_value[i]);
					map.put("remark", respremark_remark[i]);
					ss.add(map);
					i++;
				}
			}

			Map<String, Object> root = new HashMap<String, Object>();
			root.put("url", tt_request_url);
			root.put("requestHeaders", requestHeaders);
			root.put("requestParams", requestParams);
			root.put("respremark", respremarks);

			root.put("tt_requestbody", request.getParam("tt_requestbody"));
			root.put("tt_remark", request.getParam("tt_remark"));
			root.put("proxySchemeName", request.getParam("proxySchemeName"));
			root.put("proxyHostName", request.getParam("proxyHostName"));
			root.put("proxyPort", request.getParam("proxyPort"));
			root.put("tt_method", request.getParam("tt_method"));
			root.put("cookies", request.getParamArray("cookies"));

			root.put("resp_demo", request.getParam("resp_demo"));

			String dir = getTemplateDir();
			File dirF = new File(dir);
			if (!dirF.exists()) {
				dirF.mkdirs();
			}
			File file = null;
			if (isAbspath == true) {
				file = new File(templateName);
			} else {
				file = new File(dirF, templateName);
			}

			//			if (file.exists()) {
			//				WebUtils.outputAjaxRespPojo(httpServletResponse, 1, "操作失败", "文件已经存在:"+file.getAbsolutePath());
			//				return;
			//			}

			FileUtil.writeString(Json.toJson(root), file, "utf-8");
			return WebUtils.writeSuccess("操作成功", "模板文件: " + file.getAbsolutePath(), "", request);
		} catch (Exception e) {
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	/**
	 * 删除模板文件
	 * @param request
	 * @param httpServletResponse
	 * @param templateName
	 * @throws Exception
	 */
	@RequestPath(value = "/deleteTemplate")
	public static AjaxRespPojo deleteTemplate(HttpRequest request, String templateName, Boolean isAbspath) throws Exception {
		try {
			String dir = getTemplateDir();
			File dirF = new File(dir);
			if (!dirF.exists()) {
				dirF.mkdirs();
			}
			File file = null;
			if (isAbspath == true) {
				file = new File(templateName);
			} else {
				file = new File(dirF, templateName);
			}

			if (file.exists()) {
				FileUtil.del(file);
			}

			return WebUtils.writeSuccess("操作成功", "", request);
		} catch (Exception e) {
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	@RequestPath(value = "/loadTemplate")
	public static AjaxRespPojo loadTemplate(HttpRequest request, String templateName, String templateAbsPath) throws Exception {

		try {
			String dir = getTemplateDir();
			File file = null;
			if (StrUtil.isNotBlank(templateName)) {
				file = new File(dir, templateName);
			} else if (StrUtil.isNotBlank(templateAbsPath)) {
				file = new File(templateAbsPath);
			}

			String str = FileUtil.readUtf8String(file);//.readFileToString(file, "utf-8");

			return WebUtils.writeSuccess("操作成功", "", str, request);
		} catch (Exception e) {
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	@RequestPath(value = "/renameTemplate")
	public static AjaxRespPojo renameTemplate(HttpRequest request, String newTemplateAbsPath, String oldTemplateAbsPath) throws Exception {
		try {
			File oldfile = new File(oldTemplateAbsPath);
			File newfile = new File(newTemplateAbsPath);
			FileUtil.move(oldfile, newfile, true);
			return WebUtils.writeSuccess("操作成功", "", "", request);
		} catch (Exception e) {
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	/**
	 * 
	 * @param httpServletResponse
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@RequestPath(value = "/getTemplateList")
	public static AjaxRespPojo getTemplateList(int pageSize, int pageIndex, boolean isPagination, HttpRequest request) throws Exception {
		try {
			String dir = getTemplateDir();
			File dirF = new File(dir);
			final String templateName = request.getParam("templateName");
			Collection<File> files = FileUtils.listFiles(dirF, new IOFileFilter() {
				@Override
				public boolean accept(File file) {
					if (file.isDirectory()) {
						if (file.getAbsolutePath().equals(dirF.getAbsolutePath())) {
							return false;
						}
						return true;
					} else {
						if (StrUtil.isBlank(templateName) || file.getName().contains(templateName)) {
							return true;
						}
						return false;
					}
				}

				@Override
				public boolean accept(File dir, String name) {
					if (dir.getAbsolutePath().equals(dirF.getAbsolutePath())) {
						return false;
					}
					return true;
				}

			}, TrueFileFilter.INSTANCE);

			files.remove(dirF);
			List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
			if (files != null) {
				for (File file : files) {
					Map<String, Object> map = new HashMap<String, Object>();
					map.put("name", file.getName());
					map.put("date", new Date(file.lastModified()));
					list.add(map);
				}
			}

			ListPageable listPageable = new ListPageable(pageSize, pageIndex, list);
			listPageable.setPagination(isPagination);
			return WebUtils.writeSuccess("操作成功", "", listPageable, request);
		} catch (Exception e) {
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	public static void generateData(String templatedir, String targetfile) throws IOException {
		List<Map<String, Object>> list = getTemplateTree(templatedir, true);
		FileUtil.writeString("var httpclient_data = " + Json.toJson(list) + ";", new File(targetfile), "utf-8");
	}

	@RequestPath(value = "/generateOfflineData")
	public static AjaxRespPojo generateOfflineData(HttpRequest request) throws Exception {
		try {
			String templatedir = getTemplateDir();//request.getServletContext().getRealPath("/httpclientTemplate");
			String targetfile = request.httpConfig.getPageRoot() + "/app/httpclient-lixian-data.js";

			List<Map<String, Object>> list = getTemplateTree(templatedir, Boolean.valueOf(true));
			FileUtils.writeStringToFile(new File(targetfile), "var httpclient_data = " + Json.toJson(list) + ";", "utf-8");

			return WebUtils.writeSuccess("", "", request);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return WebUtils.writeFail(e, request);
		}
	}

	public static List<Map<String, Object>> getTemplateTree(String dir, Boolean isContainData) {
		try {
			File dirF = new File(dir);
			Collection<File> files = FileUtils.listFilesAndDirs(dirF, new IOFileFilter() {
				@Override
				public boolean accept(File file) {
					return true;
				}

				@Override
				public boolean accept(File dir, String name) {
					return true;
				}
			}, TrueFileFilter.INSTANCE);

			files.remove(dirF);

			List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
			if (files != null) {
				for (File file : files) {
					String name = file.getName();
					String id = file.getAbsolutePath();

					Boolean isdir = file.isDirectory();

					if (id.equals(dirF.getAbsolutePath())) {

					}

					String pname = file.getParentFile().getName();
					String pid = file.getParentFile().getAbsolutePath();

					Map<String, Object> map = new HashMap<String, Object>();
					map.put("name", name);
					map.put("id", id);
					map.put("pname", pname);
					map.put("pId", pid);
					map.put("date", new Date(file.lastModified()));
					map.put("isdir", isdir);
					if (isContainData != null && isContainData == true && !isdir) {
						map.put("data", FileUtil.readUtf8String(file));
					}
					list.add(map);
				}
			}
			return list;
		} catch (Exception e) {
			log.error("", e);
			return null;
		}

	}

	/**
	 * 
	 * @param request
	 * @param httpServletResponse
	 * @throws Exception
	 */
	@RequestPath(value = "/getTemplateTree")
	public static AjaxRespPojo getTemplateTree(HttpRequest request, Boolean isContainData) throws Exception {
		try {
			String dir = getTemplateDir();
			List<Map<String, Object>> list = getTemplateTree(dir, isContainData);
			return WebUtils.writeSuccess("操作成功", "", list, request);
		} catch (Exception e) {
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	//	@RequestPath(value = "/getJsonString")
	//	public static AjaxRespPojo getJsonString(String proxyHostName, Integer proxyPort, String proxySchemeName, String tt_request_url, HttpRequest request, String[] cookies,
	//	        String tt_method, String tt_requestbody) throws Exception {
	//		@SuppressWarnings("unused")
	//		HttpHost proxy = null;
	//		if (!StrUtil.isBlank(proxyHostName)) {
	//			proxy = new HttpHost(proxyHostName, proxyPort, proxySchemeName);
	//		}
	//
	//		Map<String, Object> params = request.getParam();
	//
	//		appendParams(request, params, "param_name", "param_value");
	//
	//		Map<String, Object> requestHeaders = new HashMap<String, Object>();
	//		appendParams(request, requestHeaders, "header_name", "header_value");
	//		try {
	//			if (cookies != null && cookies.length > 0) {
	//				for (String cookie : cookies) {
	//					if (cookie != null && !"".equals(cookie)) {
	//						requestHeaders.put("Cookie", cookie);
	//					}
	//				}
	//			}
	//			StringConverter stringConverter = StringConverter.getInstance();
	//			stringConverter.processRequest(request, httpServletResponse);
	//		} catch (Exception e) {
	//			return WebUtils.writeFail(e, request);
	//		}
	//
	//	}

	/**
	 * 
	 * @param proxyHostName
	 * @param proxyPort
	 * @param proxySchemeName
	 * @param tt_request_url
	 * @param request
	 * @param cookies
	 * @param tt_method  get,post,put and so on
	 * @param httpServletResponse
	 * @throws Exception
	 */
	@RequestPath(value = "/getHtml")
	public static AjaxRespPojo getHtml(String proxyHostName, Integer proxyPort, String proxySchemeName, String tt_request_url, HttpRequest request, String[] cookies,
	        String tt_method, String tt_requestbody, Integer timeout) throws Exception {
		if (timeout == null) {
			timeout = 20000;
		}

		HttpHost proxy = null;
		if (!StrUtil.isBlank(proxyHostName)) {
			proxy = new HttpHost(proxyHostName, proxyPort, proxySchemeName);
		}

		Map<String, Object> requestHeaders = new HashMap<String, Object>();
		appendParams(request, requestHeaders, "header_name", "header_value");

		Map<String, Object> params = request.getParam();

		params.remove("tio_http_jsonp");
		appendParams(request, params, "param_name", "param_value");

		try {
			if (cookies != null && cookies.length > 0) {
				for (String cookie : cookies) {
					if (cookie != null && !"".equals(cookie)) {
						requestHeaders.put("Cookie", cookie);
					}
				}
			}

			while (true) {
				HttpResponse response = null;

				if ("get".equalsIgnoreCase(tt_method)) {
					List<Header> headers = HttpClientUtils.mapToHeaders(requestHeaders);
					response = HttpClientUtils.get(tt_request_url, headers, proxy);
				} else if ("post".equalsIgnoreCase(tt_method)) {
					if (!StrUtil.isBlank(tt_requestbody)) { //有请求体
						response = HttpClientUtils.post(tt_request_url, tt_requestbody, requestHeaders, proxy, timeout);
					} else {
						response = HttpClientUtils.post(tt_request_url, params, requestHeaders, proxy, timeout);
					}
				} else {
					throw new RuntimeException("only post and get are supported.");
				}

				StatusLine statusLine = response.getStatusLine();
				if (statusLine.getStatusCode() == 302) //重定向
				{
					Header[] locationHeader = response.getHeaders("Location");
					tt_request_url = locationHeader[0].getValue();

					Header[] setCookieHeaders = response.getHeaders("Set-Cookie");
					HttpClientUtils.headersToMap(HttpClientUtils.convertSetCookieToCookie(setCookieHeaders), params);

					continue;
				} else {
					String responseHtml = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));
					return WebUtils.writeSuccess("操作成功", "", responseHtml, request);
				}
			}
		} catch (Exception e) {
			//            WebUtils.outputException(httpServletResponse, e);
			log.error("", e);
			return WebUtils.writeFail(e, request);
		}
	}

	/**
	 * 
	 */
	public HttpApiToolController() {

	}
}